package com.qingxin.sys.verifier.rules;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.qingxin.sys.verifier.FormMap;
import com.qingxin.sys.verifier.VerifyMsg;
import com.qingxin.sys.verifier.VerifyRule;

/**
 * 数值范围验证<br>
 * 字段值满足指定规范的值<br>
 * 1. N			固定值
 * 2. v%N		字段值%N=v
 * 3. N1--N2	N1<=字段值<=N2
 * 4. N1~~N2	N1<字段值<N2
 * 5. N1-~N2	N1<=字段值<N2
 * 6. N1~-N2	N1<字段值<=N2
 * @author Administrator
 *
 */
public class NumberRangeRule extends VerifyRule {
	
	private String type;//number/length
	private String compare;//and/or
	private String expr;
	private List<String> exprs;

	
	public NumberRangeRule() {
		this.type = "number";
		this.compare = "or";
		this.exprs = new ArrayList<String>();
	}
	
	
	@Override
	public VerifyMsg isValid(String id, String name, String label, FormMap formMap) {
		String value = formMap.getParameter(name);
		if(exprs.size() == 0 || isEmpty(value)){
			return null;
		}
		boolean pass = false;
		BigDecimal dval = null;
		BigDecimal maxvalue = null;
		BigDecimal minvalue = null;
		try {
			if("length".equalsIgnoreCase(type)){
				dval = new BigDecimal(value.length());
				maxvalue = BigDecimal.valueOf(Integer.MAX_VALUE);
				minvalue = BigDecimal.ZERO;
			}else{
				dval = new BigDecimal(value);
				maxvalue = BigDecimal.valueOf(Double.MAX_VALUE);
				minvalue = BigDecimal.valueOf(Double.MAX_VALUE).negate();
			}
			boolean all = "and".equalsIgnoreCase(compare);
			for(String expr : exprs) {
				boolean valid = false;
				if(expr.matches("^-?\\d+(\\.\\d+)?$")){
					valid = (new BigDecimal(expr)).equals(dval);
				}
				else if(expr.matches("^(-?\\d+(\\.\\d+)?|MIN)(([-~]{2})|%)(-?\\d+(\\.\\d+)?|MAX)$")){
					Matcher m = Pattern.compile("^(-?\\d+(\\.\\d+)?|MIN)(([-~]{2})|%)(-?\\d+(\\.\\d+)?|MAX)$").matcher(expr);
					if(m.find()){
						String v1 = m.group(1);
						String op = m.group(3);
						String v2 = m.group(5);
						BigDecimal dv1 = null;
						BigDecimal dv2 = null;
						if("MIN".equals(v1)){
							dv1 = minvalue;
						}else{
							dv1 = new BigDecimal(v1);
						}
						if("MAX".equals(v2)){
							dv2 = maxvalue;
						}else{
							dv2 = new BigDecimal(v2);
						}
						if("%".equals(op)){
							valid = dval.remainder(dv2).equals(dv1);
						}else if("--".equals(op)){
							valid = dv1.compareTo(dval) <= 0 && dv2.compareTo(dval) >= 0;
						}else if("~~".equals(op)){
							valid = dv1.compareTo(dval) < 0 && dv2.compareTo(dval) > 0;
						}else if("-~".equals(op)){
							valid = dv1.compareTo(dval) <= 0 && dv2.compareTo(dval) > 0;
						}else if("~-".equals(op)){
							valid = dv1.compareTo(dval) < 0 && dv2.compareTo(dval) >= 0;
						}
					}
				}
				if(!all && valid){
					pass = true;
					break;
				}
				if(all && !valid){
					break;
				}
			}//for
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		if(!pass){
			String message = createMessage(null, "{name}", label, "{label}", label);
			return new VerifyMsg(id, name, label, this.getClass().getSimpleName(), message);
		}
		
		return null;
	}
	
	
	@Override
	public Map<String, Object> getRuleCfg(String name, String label) {
		if(exprs.size() == 0){
			return null;
		}
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("rtype", "numrange");
		map.put("type", type);
		map.put("compare", compare);
		map.put("exprs", exprs);
		
		String errormsg = createMessage(null, "{name}", label, "{label}", label);
		if(!isEmpty(errormsg)){
			map.put("error", errormsg);
		}
		
		return map;
	}
	
	
	
	@Override
	protected void handleRuleArg(String arg) {
		super.handleRuleArg(arg);
		if("a".equals(arg)){
			setCompare("and");
		}else if("o".equals(arg)){
			setCompare("or");
		}else if("n".equals(arg)){
			setType("number");
		}else if("l".equals(arg)){
			setType("length");
		}
	}
	
	
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
	public String getCompare() {
		return compare;
	}
	public void setCompare(String compare) {
		this.compare = compare;
	}
	public String getExpr() {
		return expr;
	}
	public void setExpr(String expr) {
		this.expr = expr;
		String[] arr = expr.split("[,;]");
		for(String a : arr){
			if(!isEmpty(a)){
				exprs.add(a);
			}
		}
	}
	public List<String> getExprs() {
		return exprs;
	}
	public void setExprs(List<String> exprs) {
		this.exprs = exprs;
	}
	public void addExpr(String expr){
		exprs.add(expr);
	}
	
	
}
